#ifndef USMARTPOINTER_HH
#define USMARTPOINTER_HH

template<typename T>
class uSmartPointer {
private:
	struct counter {
		int references;
		pthread_mutex_t lock;
	};
	
	T* p;
	struct counter* c;
public:
	
	uSmartPointer() {
		p=0;
		c=0;
	}
	
	explicit uSmartPointer(T* pointer) {
		p=pointer;
		c=new struct counter;
		c->references=1;
		pthread_mutex_init(&(c->lock),NULL);
	}
	
	uSmartPointer(const uSmartPointer& other) {
		if(other.c==0) {
			p=0;
			c=0;
			return;
		}
		other.lockme();
		p=other.p;
		c=other.c;
		++(c->references);
		other.unlockme();
	}
	
	uSmartPointer& operator=(const uSmartPointer& other) {
		if(c==other.c) return *this;
		if(c!=0) { //TODO: this one needs a lock
			//delete a reference
			--(c->references);
			if(c->references==0)  {
				delete p;
				delete c;
			}
		}
		
		other.lockme();
		p=other.p;
		c=other.c;
		++(c->references);
		other.unlockme();
		
		return *this;
	}
	
	/**
	 * Nobody really should be able to access our objects while they are being destructed, but to be sure we'll lock this too
	 */
	virtual ~uSmartPointer() {
		if(c==0) return;
		lockme();
		--(c->references);
		int localrefCount=c->references;
		unlockme();
		if(localrefCount==0)  {
			delete p;
			delete c;
		}
	}
	
	/**
	 * gotta lock those two too becaues assignment might happen at the time(not in our project though
	 */
	T& operator*() const {
		lockme();
		T* tp=p;
		unlockme();
		return *tp;
	}
	
	T* operator->() const {
		lockme();
		T* tp=p;
		unlockme();
		return tp;
	}
	
private:
	
	int lockme() const {
		return pthread_mutex_lock(&(c->lock));
	}
	
	int unlockme() const {
		return pthread_mutex_unlock(&(c->lock));
	}
	
};

#endif